﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WooCoo.Tools
{
    public static class TaskHelpers
    {
        [StructLayout(LayoutKind.Sequential, Size = 1)]
        private struct AsyncVoid
        {
        }
        private static class CancelCache<TResult>
        {
            public static readonly Task<TResult> Canceled = TaskHelpers.CancelCache<TResult>.GetCancelledTask();
            private static Task<TResult> GetCancelledTask()
            {
                TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
                taskCompletionSource.SetCanceled();
                return taskCompletionSource.Task;
            }
        }
        private static readonly Task _defaultCompleted = TaskHelpers.FromResult<TaskHelpers.AsyncVoid>(default(TaskHelpers.AsyncVoid));
        private static readonly Task<object> _completedTaskReturningNull = TaskHelpers.FromResult<object>(null);
        internal static Task Canceled()
        {
            return TaskHelpers.CancelCache<TaskHelpers.AsyncVoid>.Canceled;
        }
        internal static Task<TResult> Canceled<TResult>()
        {
            return TaskHelpers.CancelCache<TResult>.Canceled;
        }
        public static Task Completed()
        {
            return TaskHelpers._defaultCompleted;
        }
        internal static Task FromError(Exception exception)
        {
            return TaskHelpers.FromError<TaskHelpers.AsyncVoid>(exception);
        }
        internal static Task<TResult> FromError<TResult>(Exception exception)
        {
            TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
            taskCompletionSource.SetException(exception);
            return taskCompletionSource.Task;
        }
        internal static Task FromErrors(IEnumerable<Exception> exceptions)
        {
            return TaskHelpers.FromErrors<TaskHelpers.AsyncVoid>(exceptions);
        }
        internal static Task<TResult> FromErrors<TResult>(IEnumerable<Exception> exceptions)
        {
            TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
            taskCompletionSource.SetException(exceptions);
            return taskCompletionSource.Task;
        }
        internal static Task<TResult> FromResult<TResult>(TResult result)
        {
            TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
            taskCompletionSource.SetResult(result);
            return taskCompletionSource.Task;
        }
        internal static Task<object> NullResult()
        {
            return TaskHelpers._completedTaskReturningNull;
        }
        internal static bool SetIfTaskFailed<TResult>(this TaskCompletionSource<TResult> tcs, Task source)
        {
            switch (source.Status)
            {
                case TaskStatus.Canceled:
                case TaskStatus.Faulted:
                    return tcs.TrySetFromTask(source);
                default:
                    return false;
            }
        }
        internal static bool TrySetFromTask<TResult>(this TaskCompletionSource<TResult> tcs, Task source)
        {
            if (source.Status == TaskStatus.Canceled)
            {
                return tcs.TrySetCanceled();
            }
            if (source.Status == TaskStatus.Faulted)
            {
                return tcs.TrySetException(source.Exception.InnerExceptions);
            }
            if (source.Status == TaskStatus.RanToCompletion)
            {
                Task<TResult> task = source as Task<TResult>;
                return tcs.TrySetResult((task == null) ? default(TResult) : task.Result);
            }
            return false;
        }
        internal static bool TrySetFromTask<TResult>(this TaskCompletionSource<Task<TResult>> tcs, Task source)
        {
            if (source.Status == TaskStatus.Canceled)
            {
                return tcs.TrySetCanceled();
            }
            if (source.Status == TaskStatus.Faulted)
            {
                return tcs.TrySetException(source.Exception.InnerExceptions);
            }
            if (source.Status != TaskStatus.RanToCompletion)
            {
                return false;
            }
            Task<Task<TResult>> task = source as Task<Task<TResult>>;
            if (task != null)
            {
                return tcs.TrySetResult(task.Result);
            }
            Task<TResult> task2 = source as Task<TResult>;
            if (task2 != null)
            {
                return tcs.TrySetResult(task2);
            }
            return tcs.TrySetResult(TaskHelpers.FromResult<TResult>(default(TResult)));
        }
    }
}
